package com.example.codegen;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

public class Variable implements Expression {
    // please handle null for each language in the toXXX method
    public String identifier;
    // update: may a variable in here
    public Optional<String[]> indexes;

    public Variable(String identifier, Optional<String[]> indexes) {
        this.identifier = identifier;
        // filter the empty string
        this.indexes = indexes.map(indexes1 -> Arrays.stream(indexes1).filter(index -> !index.isEmpty()).toArray(String[]::new));
    }
    public static Set<String> keywords = new HashSet<>();
    static {
        String[] words = {
                "as", "abstract", "break", "Bool", "case", "catch", "class", "const", "continue",
                "Char", "do", "else", "enum", "extend", "for", "from", "func", "false", "finally",
                "foreign", "Float16", "Float32", "Float64", "if", "in", "is", "init", "import",
                "interface", "Int8", "Int16", "Int32", "Int64", "IntNative", "let", "mut", "main",
                "macro", "match", "Nothing", "open", "operator", "override", "prop", "public",
                "package", "private", "protected", "quote", "redef", "return", "spawn", "super",
                "static", "struct", "synchronized", "try", "this", "true", "type", "throw", "This",
                "unsafe", "Unit", "UInt8", "UInt16", "UInt32", "UInt64", "UIntNative", "var", "where", "while"
        };

        for (String word : words) {
            keywords.add(word);
        }
    }
    public boolean containUpper() {
        for (char c : identifier.toCharArray()) {
            if (Character.isUpperCase(c)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String toJava() {
        return identifier + (indexes.map(index -> "[" + String.join("][", index) + "]").orElse(""));
    }

    @Override
    public String toGo() {
        return (identifier.equals("null") ? "nil" : identifier) + (indexes.map(index -> "[" + String.join("][", index) + "]").orElse(""));
    }

    @Override
    public String toJs() {
        return identifier + (indexes.map(index -> "[" + String.join("][", index) + "]").orElse(""));
    }

    public boolean IsCSharpKeywordExpectNULL(String s) {
        if (s.equals("abstract") || s.equals("as") || s.equals("base") || s.equals("bool") || s.equals("break") || s.equals("byte") || s.equals("case") || s.equals("catch") || s.equals("char") || s.equals("checked") || s.equals("class") || s.equals("const") || s.equals("continue") || s.equals("decimal") || s.equals("default") || s.equals("delegate") || s.equals("do") || s.equals("double") || s.equals("else") || s.equals("enum") || s.equals("event") || s.equals("explicit") || s.equals("extern") || s.equals("false") || s.equals("finally") || s.equals("fixed") || s.equals("float") || s.equals("for") || s.equals("foreach") || s.equals("goto") || s.equals("if") || s.equals("implicit") || s.equals("in") || s.equals("int") || s.equals("interface") || s.equals("internal") || s.equals("is") || s.equals("lock") || s.equals("long") || s.equals("namespace") || s.equals("new") || s.equals("object") || s.equals("operator") || s.equals("out") || s.equals("override") || s.equals("params") || s.equals("private") || s.equals("protected") || s.equals("public") || s.equals("readonly") || s.equals("ref") || s.equals("return") || s.equals("sbyte") || s.equals("sealed") || s.equals("short") || s.equals("sizeof") || s.equals("stackalloc") || s.equals("static") || s.equals("string") || s.equals("struct") || s.equals("switch") || s.equals("this") || s.equals("throw") || s.equals("true") || s.equals("try") || s.equals("typeof") || s.equals("uint") || s.equals("ulong") || s.equals("unchecked") || s.equals("unsafe") || s.equals("ushort") || s.equals("using") || s.equals("virtual") || s.equals("void") || s.equals("volatile") || s.equals("while")) {
            return true;
        }
        return false;
    }

    @Override
    public String toCSharp() {
        // the null is keyword in C#
        return (IsCSharpKeywordExpectNULL(identifier) ? "@" + identifier : identifier) + (indexes.map(index -> "[" + String.join("][", index) + "]").orElse(""));
    }

    @Override
    public String toCJ() {
        String str = "";
        if(indexes.isPresent()){
            for(String s : indexes.get())
                str += ".getOrThrow()["+ s +"]";
        }
        if(keywords.contains(identifier))
            return identifier+"HadTurn" + str;
        else if(identifier.equals("null"))
            return "None" + str;
        else
            return identifier + str;
    }
}
